<?php
namespace App\Http\Controllers\Auth;

use App\Jobs\AddRegisterHongBaoJob;
use App\Jobs\AddIMFriends;
use App\Jobs\GetMobileCityIdJob;
use App\Jobs\RegisterJob;
use App\Jobs\SendWelcomeMsgJob;
use App\Libraries\Decorator\Image\CoverDecorator;
use App\Libraries\Decorator\User\UserPointDecorator;
use App\Libraries\Easemob\Easemob;
use App\Libraries\SMS\SmsSingleSender;
use App\Libraries\Tools\URL;
use App\Models\Shop\ShopFav;
use App\Models\User\SMS;
use App\Models\User\UserPwLock;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\User\User;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use JMessage\JMessage;

class LoginController extends Controller{


    protected $users;
    protected $user;

    public function __construct(User $users, CoverDecorator $cover_decorator){
        $this->users = $users;
        $this->users->addDecorator($cover_decorator);
    }
    /**
     * 登录入口
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request){
        $validator = Validator::make($request->all(), [
            'id' => 'required',
            'key' => 'required',
            'unique_id' => 'required',
            'auth_type' => 'required|in:sms,password,third_party',
            'third_party' => 'required_if:auth_type,third_party',
            'grant_type' => 'required|in:password,refresh_token',
            'refresh_token' => 'required_if:grant_type,refresh_token',
            'install' => 'in:0,1'
        ], $this->messages());

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        $this->user = $this->users->getUserObjectByOpenIdOrMobile($request->id, true, true);

        if($request->auth_type == 'sms'){
            $sms = new SMS();
            $sms_code = $sms->checkCode($request->id, $request->key);
            if(empty($sms_code)){
                return $this->sendFailResponse(400, 40002);
            }
        }

        if($request->auth_type == 'password'){
            $pw_lock = UserPwLock::where('user_id', $this->user->user_id)->first();
            if(!empty($pw_lock) && $pw_lock->login_pw >= 3){
                return $this->sendFailResponse(400, 40107);
            }
        }

        if(empty($this->user)){
            return $this->sendFailResponse(401, 40104);
        }

        $credentials = [
            'username' => [
                'id' => $request->id,
                'auth_type' => $request->auth_type,
                'ip' => $request->ip(),
            ],
            'password' => [
                'id' => $request->id,
                'key' => $request->key,
                'auth_type' => $request->auth_type
            ],
        ];

        return $this->auth_token($request->grant_type, $credentials, new Client, $request, $request['install']);
    }

    /**
     * validate error code
     * @return array
     */
    public function messages(){
        return [
            'id.required' => '10001',
            'key.required' => '10001',
            'unique_id.required' => '10001',
            'auth_type.required' => '10001',
            'third_party.required_if' => '10001',
            'grant_type.required' => '10001',
            'grant_type.in' => '10002',
            'refresh_token.required_if' => '10001',
            'install.in' => '10002',
        ];
    }

    /**
     * token授权
     * @param $grantType
     * @param array $data
     * @param Client $http
     * @param $request
     * @param int $install
     * @return \Illuminate\Http\JsonResponse
     */
    private function auth_token($grantType, array $data = [], Client $http, $request, $install=0)
    {
        try {
            $data = array_merge([
                'client_id'     => config('auth.client.id'),
                'client_secret' => config('auth.client.secret'),
                'grant_type'    => $grantType,
            ], $data);
//            if($grantType == 'password'){
//                $guzzleResponse = $http->post(config('auth.url.domain').config('auth.url.oauth_token'), [
//                    'form_params' => $data,
//                ]);
//            }else{
//                $guzzleResponse = $http->post(config('auth.url.domain').config('auth.url.refresh_token'), [
//                    'form_params' => $data,
//                ]);
//            }
            $guzzleResponse = $http->post(config('auth.url.domain').config('auth.url.oauth_token'), [
                'form_params' => $data,
            ]);

        } catch(BadResponseException $e) {
//            var_dump($e->getResponse());
            $guzzleResponse = $e->getResponse();
        }
        $response = json_decode($guzzleResponse->getBody(), true);
        if($guzzleResponse->getStatusCode() == '200'){
            $response = array_merge($response, json_decode(json_encode($this->user), true));
            $this->user->unique_id = $request['unique_id'];
            $this->user->save();
            $response['cover'] = URL::getImage($response['cover']);
            $response['birthday'] = date('Y-m-d', $response['birthday']);
            $response['third_party'] = empty($this->user->open_id)?0:1;
            $response['xiaochengxu'] = empty($this->user->x_open_id)?0:1;
            $response['fav_shop'] = ShopFav::select('shop_id')->where('user_id', $this->user->user_id)->where('status', 1)->get();
            if($install){
                dispatch(new SendWelcomeMsgJob($this->user->user_id, 1));
            }
            $this->users->addDecorator(new UserPointDecorator());
            $this->users->after($response);
            return $this->sendSuccessResponse($response);
        }elseif($guzzleResponse->getStatusCode() == '401'){
            return $this->sendFailResponse($guzzleResponse->getStatusCode(), 40102);
        }
        return $this->sendFailResponse($guzzleResponse->getStatusCode(), 50000);
    }

    /**
     * 注册
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function reg(Request $request){
        $validator = Validator::make($request->all(), [
            'third_party' => 'in:weixin,xiaochengxu',
            'open_id' => 'string|'.(!empty($request['third_party'])&&$request['third_party']=='xiaochengxu'?'unique:users,x_open_id':'unique:users,open_id'),
            'access_token' => 'string',
            'nickname' => 'required|string|max:100|unique:users,nickname,'.$request['mobile'].',mobile',
            'mobile' => ['regex:/^1[34578][0-9]{9}$/', 'required'],
            'code' => 'required|size:4',
            'unique_id' => 'required',
        ], [
            'third_party.in' => '10002',
            'open_id.string' => '10002',
            'open_id.unique' => '10010',
            'access_token.string' => '10002',
            'nickname.required' => '10001',
            'nickname.string' => '10002',
            'nickname.max' => '10002',
            'nickname.unique' => '10004',
            'mobile.regex' => '10006',
            'code.required' => '10001',
            'code.size' => '10002',
            'unique_id.required' => '10001',
        ]);

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        $sms = new SMS();
        $code = $sms->checkCode($request['mobile'], $request['code']);
        if(empty($code)){
            return $this->sendFailResponse(400,40002);
        }
        $code->status = 1;
        $code->save();
        $this->user = $this->users->getUserObjectByOpenIdOrMobile($request['mobile'], false, true);
        $nickname = preg_replace('/\s/', '', $request['nickname']);
        if($this->users->checkNicknameExist($nickname, $request['mobile'])){
            return $this->sendFailResponse(400, 10004);
        }
        try{
            if(!empty($this->user)){//如果已存在账户就仅仅绑定open_id
                if(empty($request['open_id'])){
                    return $this->sendFailResponse(400,10007);
                }
                $this->user->nickname = $nickname;
                if(!empty($request['third_party'])&&$request['third_party']=='xiaochengxu'){
                    $this->user->x_open_id = $request['open_id'];
                }else{
                    $this->user->open_id = $request['open_id'];
                }
                $this->user->save();
            }else{
                if(!empty($request['open_id'])){
                    if(!empty($request['third_party'])&&$request['third_party']=='xiaochengxu') {
                        $this->users->x_open_id = $request['open_id'];
                    }else{
                        $this->users->open_id = $request['open_id'];
                    }
                }
                $this->users->nickname = $nickname;
                $this->users->mobile = $request['mobile'];
                $this->users->reg_ip = $request->ip();
                $this->users->save();
                $this->user = $this->users->getUserObjectByOpenIdOrMobile($request['mobile'], true, true);
                //创建极光IM账号
//                Easemob::singleton()->createUser($this->users->user_id, md5($this->users->user_id), $this->users->nickname);
                $client = new JMessage(env('JMSG_APPKEY'), env('JMSG_SECRET'));
                $j_user = new \JMessage\IM\User($client);
                $j_user->register("beboy_".$this->user->user_id, md5($this->user->user_id), $this->user->nickname, URL::getImage($this->user->cover));
                //分发创建环信好友job
                dispatch(new AddIMFriends($this->users->user_id));

                //分发发送欢迎消息job
                dispatch(new SendWelcomeMsgJob($this->users->user_id));

                //分发注册红包job
                dispatch(new AddRegisterHongBaoJob($this->users->user_id));

                //分发获取手机归属城市ID Job
                dispatch(new GetMobileCityIdJob($this->users->user_id));
            }
        }catch (\Exception $e){
            return $this->sendFailResponse(400, 50000);
        }


        $credentials = [
            'username' => [
                'id' => $request['mobile'],
                'auth_type' => 'reg',
                'ip' => $request->ip(),
            ],
            'password' => [
                'id' => $request['mobile'],
                'key' => $request['code'],
                'auth_type' => 'reg'
            ],
        ];

        return $this->auth_token('password', $credentials, new Client, $request);
    }

    /**
     * 游客登录
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function guest(Request $request){
        $validator = Validator::make($request->all(), [
            'guest_id' => 'required',
        ], [
            'guest_id.required' => '10001',
        ]);

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }
        $this->user = $this->users->firstOrCreate(['guest_id'=>$request['guest_id'], 'is_guest'=>1]);
        $this->user = $this->users->where('user_id', $this->user->user_id)->first();
        $this->user->nickname = '游客_'.$this->user->user_id;
        $credentials = [
            'username' => [
                'id' => $this->user->user_id,
                'auth_type' => 'guest',
                'ip' => $request->ip(),
            ],
            'password' => [
                'id' => '',
                'key' => '',
                'auth_type' => 'guest'
            ],
        ];

        return $this->auth_token('password', $credentials, new Client, $request);
    }

    /**
     * 发送短信验证码
     * @param Request $request
     * @param SMS $sms
     * @return \Illuminate\Http\JsonResponse
     */
    public function sendSMS(Request $request, SMS $sms){
//    	Log::debug($_SERVER["REMOTE_ADDR"]);
//        if(in_array($_SERVER["REMOTE_ADDR"], ['125.70.76.17', '111.79.246.153'])){
//            return $this->sendFailResponse(500, 50000);
//        }
        $validator = Validator::make($request->all(), [
            'mobile' => ['regex:/^1[34578][0-9]{9}$/', 'required'],
        ], [
            'mobile.regex' => '10006',
            'mobile.required' => '10001',
        ]);

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        $code = rand(999, 9999);
        $app_id = env('SMS_ID');
        $app_key = env('SMS_KEY');

        if(SMS::where('mobile', $request->mobile)->where('status', 0)
                ->where('created_at', '>=', time()-86400)->count() >= 3){
            return $this->sendFailResponse(500, 50000);
        }

        if(SMS::where('ip', $_SERVER["REMOTE_ADDR"])->where('status', 0)
                ->where('created_at', '>=', time()-172800)->count() >= 3){
//            Log::debug($_SERVER["REMOTE_ADDR"]);
            return $this->sendFailResponse(500, 50000);
        }

        if(SMS::where('mobile', $request->mobile)->where('created_at', '>=', time()-60)->first()){
            return $this->sendFailResponse(500, 50000);
        }

        $sms->mobile = $request->mobile;
        $sms->code = $code;
        $sms->ip = $_SERVER["REMOTE_ADDR"];
        $sms->save();

        $sender = new SmsSingleSender($app_id, $app_key);
        $rs = $sender->send(0, 86, $request->mobile, "{$code}为您在夜城的验证码，请于10分钟内填写。如非本人操作，请忽略本短信。");
        $rs = json_decode($rs, true);
        if($rs['errmsg'] == 'OK'){
            return $this->sendSuccessResponse([]);
        }
        return $this->sendFailResponse(500, 50000);
    }
}